home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac-Source 1994 July
/
Mac-Source_July_1994.iso
/
C and C++
/
System
/
Sample 2.4 Think C distribution
/
rep.c
< prev
next >
Wrap
Text File
|
1990-07-11
|
31KB
|
990 lines
/*______________________________________________________________________
rep.c - Report Module.
Copyright © 1988, 1989, 1990 Northwestern University. Permission is granted
to use this code in your own projects, provided you give credit to both
John Norstad and Northwestern University in your about box or document.
This reusable module implements scrolling reports.
The caller supplies a rectangle in which the report should be
displayed. When the report is created the caller is returned a handle
to a report record. This handle must be passed to all subsequent
routines.
There are two types of reports.
In type 0 reports the report is intially empty, and the routines
rep_Append and rep_Fill are used to append one or more lines at a time.
The maximum report size is 32k characters of text.
In type 1 reports the text is fixed, in consecutive purgable STR#
resources specified when the report is initialized. rep_Append and
rep_Fill do nothing. The maximum report size is 8k lines of text,
with no limit on characters.
Type 0 reports are appropriate for reports generated dynamically by the
program. For example, the output of a volume scanner. Type 1 reports
are more appropriate for help windows and other kinds of fixed text.
Type 1 reports use memory more efficiently than type 0 reports, and they
can handle much larger reports (8k lines vs. 32k chars). With type 0
reports the entire report is stored in one big memory buffer, while with
type 1 reports the purgable STR# resources act as a read-only virtual
memory. Both types use unpurgeable memory, but type 0 requires
1 byte per character, while type 1 only requires 4 bytes per line.
The module is currently implemented using the list manager, and the
report handle is just a list handle. But you shouldn't rely on
this - the module could be rewritten to use TextEdit or some other kind
of code, without affecting its official interface.
Multiple reports in different rectangles can be managed simultaneously.
All of the code is placed in its own segment named "rep", except for the
routine rep_Init, which is placed in segment repi.
_____________________________________________________________________*/
#include <string.h>
#include "rep.h"
#include "utl.h"
#include "doc.h"
#define nil 0
/*______________________________________________________________________
rep_Init - Initialize a Report.
Entry: repRect = ptr to rectangle enclosing report and its scroll bar.
theWindow = ptr to window containing report.
repType = report type (0 or 1).
firstID = id of first STR# resource (type 1 only).
lDefRezID = id of LDEF (type 1 only).
cellRezID = id of CELL resource (type 1 only).
Exit: repHandle = handle to report record.
For best results, the rectangle height should be 2 more than an even
multiple of the window font's ascent plus descent plus leading
(12 for Geneva 9). This will make an even number of rows appear in
the rectangle, which makes scrolling look nice.
listDefID must be the id of the special LDEF designed just for use with
type 1 reports. You default value is 128, but you can change this if
it conflicts with your own LDEFs.
_____________________________________________________________________*/
void rep_Init (Rect *repRect, WindowPtr theWindow,
short repType, short firstID,
short lDefRezID, short cellRezID, Handle *repHandle)
{
Rect rView; /* list manager rectangle */
Rect dataBounds; /* dimensions of list */
Point cSize; /* cell size */
ListHandle theList; /* handle to list manager record */
/* Variables used only for type 1 records. */
Handle theStrings; /* handle to STR# resource */
Rect frameRect; /* rectangle enclosing the list */
auxInfo **aux; /* handle to auxiliary info */
short i; /* loop index */
short count; /* number of lines in STR# rsrc */
short *pCellArray; /* pointer into cell array */
short cellIndex; /* index in cell data */
/* Set the list manager rectangle. Inset the rectangle passed by the
caller by one pixel to accomodate a framing rectangle, and subtract
15 from the right side to accomodate the scroll bar. */
rView = *repRect;
InsetRect(&rView, 1, 1);
rView.right -= 15;
/* Create an empty list. Save the report type in the refCon field of
the list record. */
SetPt(&cSize, 0, 0);
SetRect(&dataBounds, 0, 0, 1, 0);
theList = (ListHandle) LNew(&rView, &dataBounds, cSize,
repType ? lDefRezID : 0, theWindow,
false, false, false, true);
*repHandle = (Handle) theList;
(**theList).selFlags = lOnlyOne;
(**theList).refCon = repType;
/* If type 0 return handle to empty list. */
if (!repType) return;
/* If type 1 report initialize the fixed cell data. */
/* Dispose of the empty cell block created by the LNew call. Plug in a
handle to the CELL resource precomputed by the cvrt tool. Make the
resource unpurgable. */
DisposHandle((Handle)(**theList).cells);
(**theList).cells = (DataHandle)GetResource((ResType)'CELL', cellRezID);
HNoPurge((Handle)(**theList).cells);
/* Add the proper number of rows to the list. */
count = GetHandleSize((Handle)(**theList).cells) / 3;
(void) LAddRow(count, 0, theList);
/* Initialize the cell array. */
pCellArray = (**theList).cellArray;
cellIndex = 0;
while (count--) {
*pCellArray++ = cellIndex;
cellIndex += 3;
};
/* Create and initialize the auxiliary information. */
aux = (auxInfo**)NewHandle(500);
(**theList).userHandle = (Handle)aux;
(**aux).cachedPictID = 0;
SetResLoad(false);
for (i=0; true; i++) {
theStrings = GetResource('STR#', firstID + i);
if (!theStrings) break;
(**aux).auxArray[i] = theStrings;
};
SetResLoad(true);
(**aux).auxArray[i] = 0;
SetHandleSize((Handle)aux, 4*i + sizeof(auxInfo));
/* Invalidate the list rectangle. */
frameRect = (**theList).rView;
frameRect.right += 15;
InvalRect(&frameRect);
}
/*______________________________________________________________________
rep_Append - Append One Line to a Report.
Entry: repHandle = handle to report record.
repLine = ptr to pascal string to append.
drawIt = true to draw the new string, false to not draw it.
scroll = true to scroll the report to make the new line
visible.
The new line is appended to the end of the report.
If you want the report lines to become visible immediately, specify
drawIt=true and scroll=true. The result is similar to the behavior of
a dumb glass teletype, with the exception that the user can scroll
back to previous screens.
If you want to build the report invisibly and then display it,
specify drawIt=false and scroll=false. Then, when the report is
complete, simply invalidate the rectangle. This will generate an
update event, and rep_Update will display the report.
Don't forget to do a SetPort to the window containing the report
before calling this routine.
The routine simply returns for type 1 reports.
_____________________________________________________________________*/
void rep_Append (Handle repHandle, Str255 *repLine,
Boolean drawIt, Boolean scroll)
{
ListHandle theList; /* handle to list record */
Cell theCell; /* new cell to be added */
theList = (ListHandle) repHandle;
if ((**theList).refCon) return;
SetPt(&theCell, 0, (**theList).dataBounds.bottom);
LDoDraw(drawIt, theList);
(void) LAddRow(1, theCell.v, theList);
if (scroll) LScroll(0, theCell.v, theList);
LSetCell((Ptr)repLine+1, (short)(*repLine)[0], theCell, theList);
}
/*______________________________________________________________________
rep_Fill - Append Lines to a Report from an STR# resource.
Entry: repHandle = handle to report record.
id = resource id of STR# resource.
scroll = true if report should be scrolled to show last line.
The new lines are appended to the end of the report.
Don't forget to do a SetPort to the window containing the report
before calling this routine.
The routine simply returns for type 1 reports.
_____________________________________________________________________*/
void rep_Fill (Handle repHandle, short id,
Boolean scroll)
{
Handle theStrings; /* handle to STR# resource */
ListHandle theList; /* handle to list record */
unsigned char *p; /* pointer to current loc in STR# resource */
short count; /* number of lines left to append */
Point theCell; /* new cell to be added */
Rect frameRect; /* rectangle enclosing the list */
theList = (ListHandle) repHandle;
if ((**theList).refCon) return;
SetPt(&theCell, 0, (**theList).dataBounds.bottom);
theStrings = GetResource('STR#', id);
MoveHHi(theStrings);
HLock(theStrings);
p = (unsigned char *)*theStrings;
count = *((short*) p);
p += 2;
LDoDraw(false, theList);
(void) LAddRow(count, theCell.v, theList);
while (count-- > 0) {
LSetCell((Ptr)p+1, (short)*p, theCell, theList);
p += *p + 1;
theCell.v++;
};
HUnlock(theStrings);
if (scroll) LScroll(0, theCell.v, theList);
LDoDraw(true, theList);
frameRect = (**theList).rView;
frameRect.right += 15;
InvalRect(&frameRect);
};
/*______________________________________________________________________
rep_Scroll - Process a Mouse Hit in a Scroll Bar.
Entry: repHandle = handle to report record.
where = pointer to mouse click location, in local coords.
Call this routine to respond to a mouse hit in the scroll bar.
For convenience, you can call it for a mouse hit anywhere in the entire
report rectangle. The routine checks to make sure the hit is
really in the actual scroll bar, and returns if it isn't.
Note that mouse down events in the report proper are ignored by this
routine. This is the routine you should call if you do not wish to
allow users to select report lines.
Don't forget to do a SetPort to the window containing the report
before calling this routine.
_____________________________________________________________________*/
void rep_Scroll (Handle repHandle, Point where)
{
ListHandle theList; /* handle to list record */
theList = (ListHandle) repHandle;
if (!PtInRect(where, &(**((**theList).vScroll)).contrlRect)) return;
LDoDraw(true, theList);
(void) LClick(where, 0, theList);
}
/*______________________________________________________________________
rep_Click - Process a Mouse Down in a Report.
Entry: repHandle = handle to report record.
where = pointer to mouse click location, in local coords.
Exit: function result = selected line number, or -1 if none.
Call this routine to respond to a mouse hit in the report rectangle.
If the mouse hit is in the scroll bar, the report is scrolled.
Otherwise, a report line may be selected, in which case the routine
immediately deselects the line and returns its line number.
Note that mouse down events in the report proper are not ignored by
this routine. This is the routine you should call if you wish to
allow users to select report lines.
This routine can be used only with type 0 reports. It simply returns
-1 for type 1 reports.
Don't forget to do a SetPort to the window containing the report
before calling this routine.
_____________________________________________________________________*/
short rep_Click (Handle repHandle, Point where)
{
ListHandle theList; /* handle to list record */
Cell theCell; /* selected cell */
theList = (ListHandle) repHandle;
if ((**theList).refCon) return -1;
LDoDraw(true, theList);
(void) LClick(where, 0, theList);
theCell.h = theCell.v = 0;
if (LGetSelect(true, &theCell, theList)) {
LSetSelect(false, theCell, theList);
return theCell.v;
} else {
return -1;
};
}
/*______________________________________________________________________
rep_Update - Process an Update Event.
Entry: repHandle = handle to report record.
This routine should be called whenever an update event occurs for
the window containing the report. The report, scroll bar, and a
rectangle framing the whole thing are drawn. The report is drawn
using the current window font.
Don't forget to do a SetPort to the window containing the report
before calling this routine, and call BeginUpdate.
_____________________________________________________________________*/
void rep_Update (Handle repHandle)
{
ListHandle theList; /* handle to list record */
Rect frameRect; /* rectangle to be framed */
theList = (ListHandle) repHandle;
/* Draw the framing rectangle. */
frameRect = (**theList).rView;
frameRect.right += 15;
InsetRect(&frameRect, -1, -1);
FrameRect(&frameRect);
/* Call LUpdate to redraw the list and the scroll bar. */
LDoDraw(true, theList);
LUpdate((**theList).port->visRgn, theList);
/* The following FrameRect is a cludge for when an update event occurs
when the scroll bar is inactive (e.g., if a screen saver deactivates).
In this case the LUpdate call doesn't redraw the enclosing rectangle of
the scroll bar, because it thinks it's invisible. So we redraw it
here. */
FrameRect(&(**((**theList).vScroll)).contrlRect);
}
/*______________________________________________________________________
rep_Activate - Process an Activate or Deactivate Event.
Entry: repHandle = handle to report record.
activate = true to activate, false to deactivate.
This routine should be called whenever an activate or deactivate
event occurs. All it does is hilite or unhilite the scroll
bar. You should also call it to temporarily disable the scroll
bar, e.g., during generation of a report, when you aren't checking
for mouse hits anyway. This avoids the ugly "bouncing thumb"
effect.
Don't forget to do a SetPort to the window containing the report
before calling this routine.
_____________________________________________________________________*/
void rep_Activate (Handle repHandle, Boolean active)
{
ListHandle theList; /* handle to list record */
Rect scrollRect; /* scroll bar rectangle */
theList = (ListHandle) repHandle;
LDoDraw(true, theList);
LActivate(active, theList);
/* The following code fixes what look like bugs in the LActivate
routine.
On an activate event LActivate doesn't properly hilite
the scroll bar. We invalidate the scroll bar in this case, to
force an update event. This causes rep_Update to be called, which
in turn calls LUpdate, which redraws it properly hilited.
On a deactivate event LActivate erases the entire scroll bar,
including its enclosing rectangle. We want just the interior
erased, so we have to do a FrameRect. Also, for some reason
LActivate invalidates the scroll bar in this case, which generates
an update event. This produces an ugly blip when the scroll bar is
erased and redrawn by LUpdate in the subsequent call to rep_Update.
So we validate the scroll bar rectangle to prevent the update event.
Apparently LActivate is invalidating the scroll bar on deactivate
events, but not on activate events. It seems to me that it should
be exactly the other way around. But what do I know.
I don't pretend to really understand what's going on here. But
my cludges here and in rep_Update seem to fix the problems. */
scrollRect = (**((**theList).vScroll)).contrlRect;
if (active){
InvalRect(&scrollRect);
} else {
FrameRect(&scrollRect);
ValidRect(&scrollRect);
};
}
/*______________________________________________________________________
Write0 - Write the Report File for a Type 0 Report.
Entry: theList = handle to list record.
refNum = file reference number.
Exit: function result = result code.
_____________________________________________________________________*/
static OSErr Write0 (ListHandle theList, short refNum)
{
OSErr rCode; /* result code */
Handle theCells; /* handle to the list cell data */
unsigned char *buf; /* ptr to beginning of output buffer */
unsigned char *pTo; /* current position in output buffer */
unsigned char *pFrom; /* current position in input buffer */
short *cellArray; /* current position in cell array */
short nLines; /* number of lines left to write */
short nBytes; /* number of bytes to copy */
long count; /* number of bytes to write to file */
/* Get a buffer big enough to hold the entire file. */
theCells = (Handle)(**theList).cells;
nLines = (**theList).dataBounds.bottom;
pTo = buf = (unsigned char *)NewPtr(GetHandleSize(theCells) + nLines);
/* Copy cell data from the list to the buffer, adding a return
character at the end of each line. */
MoveHHi(theCells);
HLock(theCells);
pFrom = (unsigned char *)*theCells;
cellArray = (**theList).cellArray;
while (nLines--) {
nBytes = *(cellArray+1) - *cellArray;
memcpy(pTo, pFrom, nBytes);
pFrom += nBytes;
pTo += nBytes;
*pTo++ = '\r';
cellArray++;
};
HUnlock(theCells);
/* Write the buffer to the file and dispose of the buffer. */
count = pTo-buf;
rCode = FSWrite(refNum, &count, buf);
DisposPtr(buf);
return rCode;
}
/*______________________________________________________________________
Write1 - Write the Report File for a Type 1 Report.
Entry: theList = handle to list record.
refNum = file reference number.
Exit: function result = result code.
_____________________________________________________________________*/
static OSErr Write1 (ListHandle theList, short refNum)
{
OSErr rCode; /* result code */
auxInfo **aux; /* handle to auxiliary info */
short i; /* index in STR# handle array */
Handle theStrings; /* handle to STR# resource */
unsigned char *buf; /* ptr to beginning of output buffer */
unsigned char *pTo; /* current position in output buffer */
unsigned char *p; /* current position in input buffer */
unsigned char *q; /* current position in input line */
unsigned char *qEnd; /* pointer to end of input line */
short nLines; /* number of lines left to write */
short nBytes; /* number of bytes to copy */
long count; /* number of bytes to write to file */
Boolean skip; /* true if line should be skipped */
/* Get handle to auxiliary info. */
aux = (auxInfo**)(**theList).userHandle;
/* The auxiliary array contains handles to the STR# resources. The
main loop walks this array and processes one resource at a time. */
i = 0;
while (true) {
if (!(theStrings = (**aux).auxArray[i])) break;
if (!*theStrings) LoadResource(theStrings);
MoveHHi(theStrings);
HLock(theStrings);
/* Allocate a buffer big enough to write this resource. */
p = (unsigned char *)*theStrings;
nLines = *(short*)p;
p += 2;
pTo = buf = (unsigned char *)NewPtr(GetHandleSize(theStrings) - 2 + nLines);
/* Copy each line from the STR# resource to the buffer, adding
a return character at the end of each line. Don't copy lines which
contain an "only" escape sequence that specifies that this line is not
for the saved version. Don't copy lines which contain a "pict"
escape sequence. Discard other escape sequences. Don't copy
end-of-paragraph marks. */
while (nLines--) {
nBytes = *p;
q = p+1;
qEnd = q + nBytes;
skip = false;
while (q < qEnd && *q < 31) {
if (*q == docPict ||
(*q == docOnly && !(*(q+2) & docSave))) {
skip = true;
break;
};
nBytes -= *(q+1);
q += *(q+1);
};
if (!skip) {
if (nBytes && *(q+nBytes-1) == docEop) nBytes--;
memcpy(pTo, q, nBytes);
pTo += nBytes;
*pTo++ = '\r';
};
p += *p + 1;
};
HUnlock(theStrings);
/* Write the buffer to the file and dispose of the buffer. */
count = pTo - buf;
rCode = FSWrite(refNum, &count, buf);
DisposPtr(buf);
if (rCode) return rCode;
i++;
};
return noErr;
}
/*______________________________________________________________________
Write - Write the Report File.
Entry: repHandle = handle to report record.
creator = creator type for the file.
fName = pointer to file name.
vRefNum = volume reference number.
Exit: function result = result code.
_____________________________________________________________________*/
static OSErr Write (Handle repHandle, OSType creator,
Str255 *fName, short vRefNum)
{
ListHandle theList; /* handle to list record */
OSErr rCode; /* result code */
short refNum; /* file reference number */
/* Create the file. Delete it if it already exists. */
if ((rCode = Create((StringPtr)fName, vRefNum, creator, (OSType)'TEXT')) == dupFNErr) {
if (rCode = FSDelete((StringPtr)fName, vRefNum)) return rCode;
rCode = Create((StringPtr)fName, vRefNum, creator, (OSType)'TEXT');
};
if (rCode) return rCode;
/* Open the file. */
if (rCode = FSOpen((StringPtr)fName, vRefNum, &refNum)) return rCode;
/* Write the file. */
theList = (ListHandle) repHandle;
if ((**theList).refCon) {
rCode = Write1 (theList, refNum);
} else {
rCode = Write0 (theList, refNum);
};
if (rCode) {
(void) FSClose(refNum);
return rCode;
};
/* Close the file. */
if (rCode = FSClose(refNum)) return rCode;
return noErr;
}
/*______________________________________________________________________
rep_Save - Save a Report as a Text File.
Entry: repHandle = handle to report record.
prompt = pointer to SFPutFile prompt sting.
defName = pointer to default file name.
creator = creator type for the file.
menuPick = true if save operation was initiated via a
menu pick, false if it was initiated via a command key.
Exit: good = true if report saved, false if canceled by user.
function result = result code.
_____________________________________________________________________*/
OSErr rep_Save (Handle repHandle, Str255 *prompt,
Str255 *defName, OSType creator, Boolean *good, Boolean menuPick)
{
Point where; /* location of SFPutFile dialog */
SFReply reply; /* SFPutFile reply */
Handle dlgHandle; /* handle to SFPutFile DLOG resource */
Rect dlgRect; /* SFPutFile dialog rectangle */
OSErr rCode; /* result code */
CursHandle watch; /* handle to watch cursor */
/* Center the SFPutFile dialog. */
dlgHandle = GetResource('DLOG', putDlgID);
dlgRect = **(Rect**)dlgHandle;
utl_CenterDlogRect(&dlgRect, menuPick);
SetPt(&where, dlgRect.left, dlgRect.top);
/* Call SFPutFile. Return if dialog canceled. */
utl_FixStdFile();
SFPutFile(where, (StringPtr)prompt, (StringPtr)defName, nil, &reply);
if (!(*good = reply.good)) return noErr;
/* Create and write the file. */
watch = GetCursor(watchCursor);
SetCursor(*watch);
rCode = Write(repHandle, creator, (Str255 *)reply.fName, reply.vRefNum);
InitCursor();
if (rCode) {
(void) FSDelete(reply.fName, reply.vRefNum);
return rCode;
};
return FlushVol(nil, reply.vRefNum);
}
/*______________________________________________________________________
rep_Key - Process Up and Down Arrow Keys.
Entry: repHandle = handle to report record.
key = key pressed (up or down arrow).
modifiers = modifier keys.
Exit: function result = error code.
Don't forget to do a SetPort to the window containing the report
before calling this routine.
If the key down event is not an up or down arrow key then the routine
returns without doing anything.
_____________________________________________________________________*/
OSErr rep_Key (Handle repHandle, short key, short modifiers)
{
ListHandle theList; /* handle to list record */
short direc; /* +1 or -1 for direction to scroll */
short height; /* height of report in lines */
if (key == upArrow) {
direc = -1;
} else if (key == downArrow) {
direc = 1;
} else {
return noErr;
};
theList = (ListHandle) repHandle;
LDoDraw(true, theList);
if (modifiers & cmdKey) {
if (modifiers & shiftKey) {
LScroll(0, direc*(**theList).dataBounds.bottom, theList);
} else {
height = ((**theList).rView.bottom - (**theList).rView.top) /
(**theList).cellSize.v - 1;
LScroll(0, direc*height, theList);
};
} else {
LScroll(0, direc, theList);
};
return noErr;
}
/*______________________________________________________________________
rep_Jump - Scroll (jump) to a Specified Line.
Entry: repHandle = handle to report record.
lineNum = line number to jump to.
doDraw = true to redraw the report rectangle.
Don't forget to do a SetPort to the window containing the report
before calling this routine.
_____________________________________________________________________*/
void rep_Jump (Handle repHandle, short lineNum, Boolean doDraw)
{
ListHandle theList; /* handle to list record */
theList = (ListHandle) repHandle;
LDoDraw(doDraw, theList);
LScroll(0, lineNum - (**theList).visible.top, theList);
}
/*______________________________________________________________________
rep_Clear - Clear a Report.
Entry: repHandle = handle to report record.
Don't forget to do a SetPort to the window containing the report
before calling this routine.
The routine simply returns for type 1 reports.
_____________________________________________________________________*/
void rep_Clear (Handle repHandle)
{
ListHandle theList; /* handle to list record */
theList = (ListHandle) repHandle;
if ((**theList).refCon) return;
LDoDraw(true, theList);
LDelRow(0, 0, theList);
}
/*______________________________________________________________________
rep_Full - Check a Report to See if it's Full.
Entry: repHandle = handle to report record.
slop = number of bytes to guarantee free.
Exit: funtion result = true if not at least slop free bytes.
_____________________________________________________________________*/
Boolean rep_Full (Handle repHandle, long slop)
{
ListHandle theList; /* handle to list record */
long repSize; /* size of list cell data */
theList = (ListHandle) repHandle;
repSize = GetHandleSize((Handle)(**theList).cells);
return slop > (0x7fff - repSize);
}
/*______________________________________________________________________
rep_Dispose - Dispose of a report.
Entry: repHandle = handle to report record.
cellOption = CELL resource disposal option (type 1 reports
only):
0 = release the CELL resource.
1 = keep the CELL resource, but make it purgable.
2 = keep the CELL resource, and leave it unpurgable.
_____________________________________________________________________*/
void rep_Dispose (Handle repHandle, short cellOption)
{
ListHandle theList; /* handle to list record */
auxInfo **aux; /* handle to auxiliary info */
theList = (ListHandle) repHandle;
/* For a type 1 report, dispose of the auxiliary info, and process
the cell option. */
if ((**theList).refCon) {
aux = (auxInfo**)(**theList).userHandle;
if ((**aux).cachedPictID) DisposPtr((**aux).cachedBitMap.baseAddr);
DisposHandle((Handle)aux);
switch (cellOption) {
case 0:
ReleaseResource((Handle)(**theList).cells);
break;
case 1:
HPurge((Handle)(**theList).cells);
break;
case 2:
break;
};
(**theList).cells = (DataHandle)NewHandle(0);
};
/* Dispose of the list. */
LDispose(theList);
}
/*______________________________________________________________________
rep_GetSize - Get the Size of a Report.
Entry: repHandle = handle to report record.
Exit: function result = number of lines in report.
_____________________________________________________________________*/
short rep_GetSize (Handle repHandle)
{
ListHandle theList; /* handle to list record */
theList = (ListHandle)repHandle;
return (**theList).dataBounds.bottom;
}
/*______________________________________________________________________
rep_Tag - Lookup a Tag.
Entry: id = TAG resource id.
tag = tag to lookup in TAG resource.
Exit: function result = corresponding line number from
tag resource, or 0 if none found.
_____________________________________________________________________*/
short rep_Tag (short id, short tag)
{
Handle h; /* handle to TAG resource */
char *p; /* pointer into TAG resource */
short n; /* number of entries in TAG resource */
h = GetResource('TAG ', id);
if (!h) return 0;
p = *h;
n = *(short*)p;
p += 4;
while (n--) {
if (tag == *(short*)p) return *(short*)(p-2);
p += 4;
};
return 0;
}
/*______________________________________________________________________
rep_Height - Set New Report Height.
Entry: repHandle = handle to report record.
bottom = new bottom coord.
The new height is rounded down to the nearest multiple of the cell
height.
_____________________________________________________________________*/
void rep_Height (Handle repHandle, short bottom)
{
ListHandle theList; /* handle to list record */
short oldHeight; /* old height of list rect */
short newHeight; /* new height of list rect */
Rect inval; /* rect to invalidate */
theList = (ListHandle)repHandle;
oldHeight = (**theList).rView.bottom - (**theList).rView.top;
newHeight = bottom - (**theList).rView.top;
newHeight -= newHeight % (**theList).cellSize.v;
if (oldHeight == newHeight) return;
LDoDraw(false, theList);
LSize((**theList).rView.right - (**theList).rView.left,
newHeight, theList);
LDoDraw(true, theList);
inval = (**theList).rView;
InsetRect(&inval, -1, -1);
inval.right += 15;
inval.bottom = (**theList).port->portRect.bottom;
InvalRect(&inval);
}
/*______________________________________________________________________
rep_GetRect - Get Report Rectangle.
Entry: repHandle = handle to report record.
Exit: rect = report rectangle.
_____________________________________________________________________*/
void rep_GetRect (Handle repHandle, Rect *rect)
{
ListHandle theList; /* handle to list record */
theList = (ListHandle)repHandle;
*rect = (**theList).rView;
rect->right += 15;
}
/*______________________________________________________________________
rep_GetPos - Get Report Scroll Position.
Entry: repHandle = handle to report record.
Exit: function result = line number of top visible line in report.
_____________________________________________________________________*/
short rep_GetPos (Handle repHandle)
{
ListHandle theList; /* handle to list record. */
theList = (ListHandle)repHandle;
return (**theList).visible.top;
}